package com.relife.core.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.transaction.Transactional;

import com.relife.common.exception.BusinessException;
import com.relife.common.model.Client;
import com.relife.common.model.ClientManager;
import com.relife.common.model.Page;
import com.relife.common.utils.ReflectUtil;
import com.relife.common.utils.SmsUtil;
import com.relife.common.utils.StringUtil;
import com.relife.common.utils.SysConfig;
import com.relife.common.workflow.ProcessUtil;
import com.relife.core.entity.*;
import com.relife.core.qbc.QbcQuery;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.hibernate.criterion.Restrictions;
import org.hibernate.sql.JoinType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;



@Service("processService")
@Transactional
public class ProcessService extends BaseService {
	@Autowired
	private IdentityService identityService;

	@Autowired
	private RuntimeService runtimeService;
	@Autowired
	private HistoryService historyService;

	@Autowired
	private TaskService taskService;

	/***
	 * 流程启动
	 * 
	 * @author WU
	 * @date 2016年5月26日 下午5:46:20
	 * @param t
	 */
	public <T> void startFlow(T t) {
		Client client = ClientManager.getInstance().getClientSession();

		// 用来设置启动流程的人员ID，引擎会自动把用户ID保存到activiti:initiator中
		identityService.setAuthenticatedUserId(client.getUser().getId());

		String processKey = StringUtil.toString(ReflectUtil.getValue(t, "processKey"));
		if (StringUtil.isEmpty(processKey)) {
			ProcessConfigEntity pc = getProcessSet(t.getClass().getName(),client.getDepart().getDepartCode());
			if (pc == null) {
				throw new RuntimeException("请先配置【" + client.getCompany().getName() + "】的流程");
			}
			processKey = pc.getProcessSet().getProcesskey();
			ReflectUtil.setValue(t, "processKey", processKey);
		}
		ProcessSetEntity pSet = this.get(ProcessSetEntity.class, "processkey", processKey);

		Map<String, Object> variables = new HashMap<String, Object>();
		variables.put(ProcessUtil.COMPANY_CODE, client.getCompany().getDepartCode());
		variables.put(ProcessUtil.HANDLE_URL, pSet.getHandleurl());

		if (StringUtil.isNotEmpty(pSet.getMobilehandle())) {
			variables.put(ProcessUtil.MOBILE_HANDLE_URL, pSet.getMobilehandle());
		}
		variables.put(ProcessUtil.APPLY_USER, client.getUser().getId());
		variables.put(ProcessUtil.APPLY_NAME, client.getUser().getName());

		String businessKey = StringUtil.toString(ReflectUtil.getValue(t, "businessKey"));
		ProcessInstance pi = runtimeService.startProcessInstanceByKey(processKey, businessKey, variables);

		// 流程实例ID
		ReflectUtil.setValue(t, "processinstanceid", pi.getId());
		ReflectUtil.setValue(t, "processState", 1);
	}

	/**
	 * 执行下一步
	 * 
	 * @author WU
	 * @date 2016年6月6日 下午2:34:02
	 * @param t
	 * @param variables
	 */
	public <T> void executeNext(T t, Map<String, Object> variables) {

		/** 任务id **/
		String taskId = StringUtil.toString(ReflectUtil.getValue(t, "taskId"));

		if (taskService.createTaskQuery().taskId(taskId).active().singleResult() == null) {
			throw new BusinessException("任务已经办理，请不要重复操作！");
		}

		String flowName = this.getFlowName(taskId);

		/** 流程实例id **/
		String processinstanceid = StringUtil.toString(ReflectUtil.getValue(t, "processinstanceid"));
		/** 节点id **/
		String processId = StringUtil.toString(ReflectUtil.getValue(t, "processId"));
		/** 业务编号 **/
		String businessKey = StringUtil.toString(ReflectUtil.getValue(t, "businessKey"));

		String auditOpinion = StringUtil.toString(ReflectUtil.getValue(t, "auditOpinion"));

		Integer auditState = StringUtil.toInteger(ReflectUtil.getValue(t, "auditState"));
		if (auditState == null) {

		} else if (auditState == 0) {
			variables.put(processId.replace("Audit", "Pass"), false);
		} else if (auditState == 1) {
			variables.put(processId.replace("Audit", "Pass"), true);

		}

		AppEntity app = ClientManager.getInstance().getApp();
		/** 不通过 终止流程 **/
		if (auditState != null && auditState == -1) {

			ReflectUtil.setValue(t, "processState", 10);
			runtimeService.deleteProcessInstance(processinstanceid, ClientManager.getInstance().getClientSession().getUser().getName() + "作废");

			// 短信参数
			JSONArray param = new JSONArray();
			param.add("[" + flowName);
			param.add(businessKey + "]");
			sendHandleSms(businessKey, SysConfig.STOP_SMS, param, app.getStopSms());
		} else {
			if (StringUtil.isNotEmpty(auditOpinion)) {
				taskService.addComment(taskId, processinstanceid, auditOpinion);
			}
			taskService.complete(taskId, variables);

			Task task = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).active().singleResult();
			if (task != null) {
				ReflectUtil.setValue(t, "taskId", task.getId());
				ReflectUtil.setValue(t, "processId", task.getTaskDefinitionKey());
				ReflectUtil.setValue(t, "processName", task.getName());

				if (auditState != null && auditState == 0) {
					ReflectUtil.setValue(t, "processState", 2);

					// 短信参数
					JSONArray param = new JSONArray();
					param.add("[" + flowName);
					param.add(businessKey + "]");
					sendHandleSms(businessKey, SysConfig.BACK_SMS, param, app.getBackSms());
					sendTaskSms(processinstanceid, SysConfig.TASK_SMS, param, app.getTaskSms());
				} else {
					ReflectUtil.setValue(t, "processState", 3);

					// 短信参数
					JSONArray param = new JSONArray();
					param.add("[" + flowName);
					param.add(businessKey + "]");
					sendTaskSms(processinstanceid, SysConfig.TASK_SMS, param, app.getTaskSms());
					param.add("[" + task.getName() + "]");
					sendHandleSms(businessKey, SysConfig.HANDLE_SMS, param, app.getHandleSms());
				}
			} else {
				ReflectUtil.setValue(t, "processId", "endevent1");
				ReflectUtil.setValue(t, "processName", "已完成");
				ReflectUtil.setValue(t, "processState", 4);

				// 短信参数
				JSONArray param = new JSONArray();
				param.add("[" + flowName);
				param.add(businessKey + "]");
				sendHandleSms(businessKey, SysConfig.HANDLE_END_SMS, param, app.getHandleEndSms());
			}
		}
	}

	/**
	 * 发送待办信息
	 * 
	 * @author WU
	 * @date 2017年3月22日 下午3:46:43
	 * @param pid
	 * @param msg
	 * @param param
	 * @param templateid
	 */
	private void sendTaskSms(String pid, String msg, JSONArray param, String templateid) {
		AppEntity app = ClientManager.getInstance().getApp();
		List<UserEntity> list = this.getUserListByprocessinstanceId(pid);
		// 网易短信
		if (app.getSmsType().intValue() == 1) {
			JSONArray mobiles = new JSONArray();
			for (int i = 0; i < list.size(); i++) {
				mobiles.add(list.get(i).getPhone());
			}
			SmsUtil.sendSMS(mobiles, param, templateid, String.format(msg, param.toArray()));
		} else {
			String phones = "";
			for (int i = 0; i < list.size(); i++) {
				phones += (StringUtil.isEmpty(phones) ? "" : ",") + list.get(i).getPhone();
			}
			SmsUtil.sendSMS(phones, String.format(msg, param.toArray()));
		}
	}

	/**
	 * 发送已办信息
	 * 
	 * @author WU
	 * @date 2017年3月22日 下午3:46:32
	 * @param businessKey
	 * @param msg
	 * @param param
	 * @param templateid
	 */
	private void sendHandleSms(String businessKey, String msg, JSONArray param, String templateid) {
		AppEntity app = ClientManager.getInstance().getApp();
		UserEntity user = this.getStartUser(businessKey);
		if (user != null) {
			// 网易短信
			if (app.getSmsType().intValue() == 1) {
				JSONArray mobiles = new JSONArray();
				mobiles.add(user.getPhone());
				SmsUtil.sendSMS(mobiles, param, templateid, String.format(msg, param.toArray()));
			} else {
				SmsUtil.sendSMS(user.getPhone(), String.format(msg, param.toArray()));
			}
		}
	}

	/**
	 * @author WU
	 * @date 2016年6月6日 上午9:56:07
	 * @param dutyCode
	 * @return
	 */
	public List<UserEntity> getUsersByDutyCode(String dutyCode) {
		List<UserEntity> uList = new ArrayList<UserEntity>();
		QbcQuery qbc = new QbcQuery(UserRoleEntity.class);
		qbc.createAlias("role", JoinType.INNER_JOIN);
		qbc.createAlias("user", JoinType.INNER_JOIN);
		qbc.add(Restrictions.eq("role.dutyCode", dutyCode));
		List<UserRoleEntity> urList = this.getList(qbc);
		for (int i = 0; i < urList.size(); i++) {
			uList.add(urList.get(i).getUser());
		}
		return uList;
	}

	public List<UserEntity> getUsersByDutyCode(String dutyCode, String departId) {
		List<UserEntity> uList = new ArrayList<UserEntity>();
		QbcQuery qbc = new QbcQuery(LeaderEntity.class);
		qbc.createAlias("user", JoinType.INNER_JOIN);
		qbc.add(Restrictions.eq("dutyCode", dutyCode));
		qbc.add(Restrictions.eq("depart.id", departId));
		List<LeaderEntity> urList = this.getList(qbc);
		for (int i = 0; i < urList.size(); i++) {
			uList.add(urList.get(i).getUser());
		}
		return uList;
	}

	/**
	 * 根据部门和职位获取用户
	 * 
	 * @author WU
	 * @date 2016年8月17日 下午5:09:39
	 * @param dutyCode
	 * @param departId
	 * @return
	 */
	public UserEntity getUserByDutyAndDepartId(String dutyCode, String departId) {
		QbcQuery qbc = new QbcQuery(LeaderEntity.class);
		qbc.add(Restrictions.eq("dutyCode", dutyCode));
		qbc.add(Restrictions.eq("depart.id", departId));
		LeaderEntity leader = get(qbc);
		return leader == null ? null : leader.getUser();
	}

	/**
	 * 
	 * @author WU
	 * @date 2016年6月7日 下午5:07:20
	 * @param nodeKey
	 * @param processKey
	 * @param variables
	 */
	public ProcessConfigListEntity setVariables(String nodeKey, String processKey, Map<String, Object> variables) {
		Client client = ClientManager.getInstance().getClientSession();
		ProcessConfigListEntity pcl = getProcessConfigList(nodeKey, processKey, client.getDepart().getDepartCode());
		if (pcl == null) {
			return null;
		} else if (StringUtil.isNotEmpty(pcl.getAssignee())) {
			if (pcl.getUser() != null) {
				variables.put(pcl.getAssignee(), pcl.getUser().getId());

			} else if (pcl.getRole() != null) {
				QbcQuery q = new QbcQuery(LeaderEntity.class);
				q.add(Restrictions.eq("dutyCode", pcl.getRole().getDutyCode()));
				q.add(Restrictions.eq("depart.id", client.getDepart().getId()));
				LeaderEntity leader = this.get(q);
				if (leader == null) {
					CodeEntity code = ClientManager.getInstance().getCode("dutyCode", pcl.getRole().getDutyCode());
					throw new RuntimeException("请先配置部门【" + client.getDepart().getName() + "】的【" + code.getName() + "】");
				} else {
					variables.put(pcl.getAssignee(), leader.getUser().getId());
				}
			}

		} else if (StringUtil.isNotEmpty(pcl.getGroupName())) {
			variables.put(pcl.getGroupName(), pcl.getRole().getGroupId());
		}

		return pcl;
	}

	/**
	 * 
	 * @author WU
	 * @date 2016年6月7日 下午5:07:20
	 * @param nodeKey
	 * @param processKey
	 * @param variables
	 * @param departId
	 */
	public ProcessConfigListEntity setVariables(String nodeKey, String processKey, Map<String, Object> variables, String departId) {
		Client client = ClientManager.getInstance().getClientSession();
		ProcessConfigListEntity pcl = getProcessConfigList(nodeKey, processKey, client.getDepart().getDepartCode());
		if (pcl == null) {
			return null;
		} else if (StringUtil.isNotEmpty(pcl.getAssignee())) {
			if (pcl.getUser() != null) {
				variables.put(pcl.getAssignee(), pcl.getUser().getId());

			} else if (pcl.getRole() != null) {
				QbcQuery q = new QbcQuery(LeaderEntity.class);
				q.add(Restrictions.eq("dutyCode", pcl.getRole().getDutyCode()));
				q.add(Restrictions.eq("depart.id", departId));
				LeaderEntity leader = this.get(q);
				if (leader == null) {
					CodeEntity code = ClientManager.getInstance().getCode("dutyCode", pcl.getRole().getDutyCode());
					DepartmentEntity depart = this.get(DepartmentEntity.class, departId);
					throw new RuntimeException("请先配置部门【" + depart.getName() + "】的【" + code.getName() + "】");
				} else {
					variables.put(pcl.getAssignee(), leader.getUser().getId());
				}
			}

		} else if (StringUtil.isNotEmpty(pcl.getGroupName())) {
			variables.put(pcl.getGroupName(), pcl.getRole().getGroupId());
		}

		return pcl;
	}

	/**
	 * @Title: invalidProcess
	 * @Description: 作废终止流程实例
	 * @param processinstanceid
	 * @param entity
	 *            void
	 * @throws @exception
	 * @author fly
	 * @date 2016年6月8日 上午10:15:10
	 */
	@SuppressWarnings("unchecked")
	public <T> void invalidProcess(String processinstanceid, T entity, String userName) {
		Long task = taskService.createTaskQuery().processInstanceId(processinstanceid).count();
		if (task != null && task > 0) {
			runtimeService.deleteProcessInstance(processinstanceid, userName + "作废");
		}
		entity = (T) this.get(entity.getClass(), "processinstanceid", processinstanceid);
		if (entity != null) {
			ReflectUtil.setValue(entity, "processState", 11);
			update(entity);
		}
	}

	/**
	 * 
	 * @author WU
	 * @date 2016年11月28日 下午4:18:03
	 * @param page
	 * @param where
	 */
	public void taskListData(Page page, StringBuffer where, Object... objects) {
		StringBuffer sql = new StringBuffer(SysConfig.getReportSql());
		sql.append(where.toString());
		getPage(sql.toString(), page, objects);
	}

	/**
	 * 已办列表
	 * 
	 * @author WU
	 * @date 2016年11月28日 下午4:15:11
	 * @param page
	 */
	public void historyListData(Page page, StringBuffer where, Object... objects) {
		StringBuffer sql = new StringBuffer(SysConfig.getReportSql());
		sql.append(where.toString());
		getPage(sql.toString(), page, objects);
	}

	/**
	 * 根据用户获取各个流程的待办数量
	 * 
	 * @author WU
	 * @date 2016年11月8日 下午3:05:46
	 * @return
	 */
	public List<Map<String, Object>> getTaskGroup(String userId, DepartmentEntity company) {
		return getList(SysConfig.getReportSql(), company.getDepartCode() + "%", userId, userId, company.getId());
	}

	/**
	 * 流转记录
	 * 
	 * @author WU
	 * @date 2016年11月28日 下午2:30:58
	 * @param processdefinitionid
	 */
	public List<Map<String, Object>> flowList(String processdefinitionid) {
		return getList(SysConfig.getReportSql(), processdefinitionid);
	}

	/**
	 * 
	 * @author WU
	 * @date 2017年1月16日 下午4:24:44
	 * @return
	 */
	public List<UserEntity> getUserListByprocessinstanceId(String processinstanceid) {
		Task task = taskService.createTaskQuery().processInstanceId(processinstanceid).active().singleResult();
		if (task == null) {
			return null;

		} else if (StringUtil.isNotEmpty(task.getAssignee())) {
			return this.getList(UserEntity.class, "id", task.getAssignee());

		} else {
			StringBuffer sql = new StringBuffer();
			sql.append("select m.user_id_ ID from ACT_RU_IDENTITYLINK t");
			sql.append(" left join act_id_membership m on m.group_id_=t.group_id_");
			sql.append(" where t.task_id_=? ");

			List<Map<String, Object>> list = this.getList(sql.toString(), task.getId());
			List<Object> param = new ArrayList<Object>();
			if (list != null && list.size() > 0) {
				for (int i = 0; i < list.size(); i++) {
					param.add(list.get(i).get("ID"));
				}
			}
			QbcQuery qbc = new QbcQuery(UserEntity.class);
			qbc.add(Restrictions.in("id", param.toArray()));
			return this.getList(qbc);
		}
	}

	/**
	 * 获取流程名称
	 * 
	 * @author WU
	 * @date 2017年1月17日 上午10:05:49
	 * @return
	 */
	public String getFlowName(String taskId) {
		String sql = "select p.name_ NAME from act_re_procdef p left join act_ru_task t on t.proc_def_id_=p.id_ where t.id_=?";
		Object obj = this.get(sql, taskId).get("NAME");
		return obj == null ? "" : obj.toString();
	}

	/**
	 * 获取流程发起人
	 * 
	 * @author WU
	 * @date 2017年1月17日 上午11:03:31
	 * @param businessKey
	 * @return
	 */
	public UserEntity getStartUser(String businessKey) {
		String sql = "select t.start_user_id_ ID from ACT_HI_PROCINST t where t.business_key_= ? ";
		Object id = this.get(sql, businessKey).get("ID");
		if (StringUtil.isNotEmpty(id)) {
			return this.get(UserEntity.class, id.toString());
		} else {
			return null;
		}
	}

	/**
	 * @Title: invalidProcess
	 * @Description: 追回作废流程
	 * @param processinstanceid
	 * @param businessKey
	 * @param username
	 *            void
	 * @throws @exception
	 * @author fly
	 * @date 2017年2月16日 下午4:08:48
	 */
	public void invalidProcess(String processinstanceid, String businessKey, String username) {
		runtimeService.deleteProcessInstance(processinstanceid, username + "流程作废");
	}

	/**
	 * @Title: cancelProcess
	 * @Description: 取消流程并删除流程历史记录
	 * @param processinstanceid
	 * @param businessKey
	 * @param username
	 *            void
	 * @throws @exception
	 * @author fly
	 * @date 2017年2月16日 下午4:12:00
	 */

	public void cancelProcess(String processinstanceid, String businessKey, String username) {
		Long task = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).count();
		if (task != null && task > 0) {
			runtimeService.deleteProcessInstance(processinstanceid, username + "作废");
			historyService.deleteHistoricProcessInstance(processinstanceid);
		}
	}
	
	/**
	  * @Title: getProcessSet
	  * @Description: 获取流程设置
	  * @param className
	  * @param depCode
	  * @return ProcessConfigEntity
	  * @throws 
	  * @exception
	  * @author fly
	  * @date 2017年9月5日 下午4:56:11
	 */
	
	public ProcessConfigEntity getProcessSet(String className, String depCode) {
		ProcessConfigEntity pc = null;
		for (int i = depCode.length(); i >= 6; i = i - 3) {
			DepartmentEntity department = this.get(DepartmentEntity.class, "departCode", depCode.substring(0, i));
			QbcQuery qbc = new QbcQuery(ProcessConfigEntity.class);
			qbc.add(Restrictions.eq("depart.id", department.getId()));
			qbc.createAlias("processSet", JoinType.INNER_JOIN);
			qbc.add(Restrictions.eq("processSet.entityname", className));
			pc = this.get(qbc);
			if (pc != null) {
				break;
			}
		}
		return pc;
	}
	/**
	 * 
	  * @Title: getProcessConfigList
	  * @Description: 获取流程配置清单
	  * @param nodeKey
	  * @param processKey
	  * @param depCode
	  * @return ProcessConfigListEntity
	  * @throws 
	  * @exception
	  * @author fly
	  * @date 2017年9月5日 下午4:56:32
	 */
	public ProcessConfigListEntity getProcessConfigList(String nodeKey, String processKey, String depCode) {
		ProcessConfigListEntity pcl = null;
		for (int i = depCode.length(); i >= 6; i = i - 3) {
			DepartmentEntity department = this.get(DepartmentEntity.class, "departCode", depCode.substring(0, i));
			QbcQuery qbc = new QbcQuery(ProcessConfigListEntity.class);
			qbc.add(Restrictions.eq("nodeKey", nodeKey));
			qbc.add(Restrictions.eq("processKey", processKey));
			qbc.add(Restrictions.eq("departId", department.getId()));
			pcl = this.get(qbc);
			if (pcl != null) {
				break;
			}
		}

		return pcl;
	}
}
